// -----------------------------
// Author: 		Dhaenens Gert 
// Creation: 	8/6/2013 10:50:54 PM				
// -----------------------------

#ifndef _LuaSafeCall_h
#define _LuaSafeCall_h

#include "Lua.h"
#include "LuaDataType.h"

namespace ObjectLua
{

	namespace Internal
	{

		/*
		//	Function used to safely call
		//	functions wich could possibly
		//	have a void return type
		//	0 Arguments
		*/
		template<typename R>
		struct SafeCall_0
		{
			int operator()(Lua* lpLua, R (*lpFunction)())
			{
				R returnArg = lpFunction();
				LuaDataType<R>::push(lpLua,returnArg);
				return 1;
			}
		};
		template<>
		struct SafeCall_0<void>
		{
			int operator()(Lua* lpLua, void (*lpFunction)())
			{
				lpFunction();
				return 0;
			}
		};



		/*
		//	Function used to safely call
		//	functions wich could possibly
		//	have a void return type
		//	1 Argument
		*/
		template<typename R, typename P0>
		struct SafeCall_1
		{
			int operator()(Lua* lpLua, R(*lpFunction)(P0))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua, 1);
				R returnArg = lpFunction(arg0);
				LuaDataType<R>::push(lpLua,returnArg);
				return 1;
			}
		};
		template<typename P0>
		struct SafeCall_1<void,P0>
		{
			int operator()(Lua* lpLua, void(*lpFunction)(P0))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua, 1);
				lpFunction(arg0);
				return 0;
			}
		};



		/*
		//	Function used to safely call
		//	functions wich could possibly
		//	have a void return type
		//	2 Arguments
		*/
		template<typename R, typename P0, typename P1>
		struct SafeCall_2
		{
			int operator()(Lua* lpLua, R (*lpFunction)(P0,P1))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua,1);
				P1 arg1 = LuaDataType<P1>::get(lpLua,2);
				R returnArg = lpFunction(arg0,arg1);
				LuaDataType<R>::push(lpLua,returnArg);
				return 1;
			}
		};
		template<typename P0, typename P1>
		struct SafeCall_2<void,P0,P1>
		{
			int operator()(Lua* lpLua, void (*lpFunction)(P0,P1))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua,1);
				P1 arg1 = LuaDataType<P1>::get(lpLua,2);
				lpFunction(arg0,arg1);
				return 0;
			}
		};



		/*
		//	Function used to safely call
		//	functions wich could possibly
		//	have a void return type
		//	3 Arguments
		*/
		template<typename R, typename P0, typename P1, typename P2>
		struct SafeCall_3
		{
			int operator()(Lua* lpLua, R(*lpFunction)(P0, P1, P2))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua,1);
				P1 arg1 = LuaDataType<P1>::get(lpLua,2);
				P2 arg2 = LuaDataType<P2>::get(lpLua,3);
				R returnArg = lpFunction(arg0,arg1,arg2);
				LuaDataType<R>::push(lpLua,returnArg);
				return 1;
			}
		};
		template<typename P0, typename P1, typename P2>
		struct SafeCall_3<void,P0,P1,P2>
		{
			int operator()(Lua* lpLua, void(*lpFunction)(P0, P1, P2))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua,1);
				P1 arg1 = LuaDataType<P1>::get(lpLua,2);
				P2 arg2 = LuaDataType<P2>::get(lpLua,3);
				lpFunction(arg0,arg1,arg2);
				return 0;
			}
		};



		/*
		//	Function used to safely call
		//	functions wich could possibly
		//	have a void return type
		//	4 Arguments
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3>
		struct SafeCall_4
		{
			int operator()(Lua* lpLua, R(*lpFunction)(P0, P1, P2, P3))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua,1);
				P1 arg1 = LuaDataType<P1>::get(lpLua,2);
				P2 arg2 = LuaDataType<P2>::get(lpLua,3);
				P3 arg3 = LuaDataType<P3>::get(lpLua,4);
				R returnArg = lpFunction(arg0,arg1,arg2,arg3);
				LuaDataType<R>::push(lpLua,returnArg);
				return 1;
			}
		};
		template<typename P0, typename P1, typename P2, typename P3>
		struct SafeCall_4<void,P0,P1,P2,P3>
		{
			int operator()(Lua* lpLua, void(*lpFunction)(P0, P1, P2, P3))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua,1);
				P1 arg1 = LuaDataType<P1>::get(lpLua,2);
				P2 arg2 = LuaDataType<P2>::get(lpLua,3);
				P3 arg3 = LuaDataType<P3>::get(lpLua,4);
				lpFunction(arg0,arg1,arg2,arg3);
				return 0;
			}
		};



		/*
		//	Function used to safely call
		//	functions wich could possibly
		//	have a void return type
		//	5 Arguments
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4>
		struct SafeCall_5
		{
			int operator()(Lua* lpLua, R(*lpFunction)(P0, P1, P2, P3, P4))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua,1);
				P1 arg1 = LuaDataType<P1>::get(lpLua,2);
				P2 arg2 = LuaDataType<P2>::get(lpLua,3);
				P3 arg3 = LuaDataType<P3>::get(lpLua,4);
				P4 arg4 = LuaDataType<P4>::get(lpLua,5);
				R returnArg = lpFunction(arg0,arg1,arg2,arg3,arg4);
				LuaDataType<R>::push(lpLua,returnArg);
				return 1;
			}
		};
		template<typename P0, typename P1, typename P2, typename P3, typename P4>
		struct SafeCall_5<void,P0,P1,P2,P3,P4>
		{
			int operator()(Lua* lpLua, void(*lpFunction)(P0, P1, P2, P3, P4))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua,1);
				P1 arg1 = LuaDataType<P1>::get(lpLua,2);
				P2 arg2 = LuaDataType<P2>::get(lpLua,3);
				P3 arg3 = LuaDataType<P3>::get(lpLua,4);
				P4 arg4 = LuaDataType<P4>::get(lpLua,5);
				lpFunction(arg0,arg1,arg2,arg3,arg4);
				return 0;
			}
		};



		/*
		//	Function used to safely call
		//	functions wich could possibly
		//	have a void return type
		//	6 Arguments
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
		struct SafeCall_6
		{
			int operator()(Lua* lpLua, R(*lpFunction)(P0, P1, P2, P3, P4, P5))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua,1);
				P1 arg1 = LuaDataType<P1>::get(lpLua,2);
				P2 arg2 = LuaDataType<P2>::get(lpLua,3);
				P3 arg3 = LuaDataType<P3>::get(lpLua,4);
				P4 arg4 = LuaDataType<P4>::get(lpLua,5);
				P5 arg5 = LuaDataType<P5>::get(lpLua,6);
				R returnArg = lpFunction(arg0,arg1,arg2,arg3,arg4,arg5);
				LuaDataType<R>::push(lpLua,returnArg);
				return 1;
			}
		};
		template<typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
		struct SafeCall_6<void,P0,P1,P2,P3,P4,P5>
		{
			int operator()(Lua* lpLua, void(*lpFunction)(P0, P1, P2, P3, P4, P5))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua,1);
				P1 arg1 = LuaDataType<P1>::get(lpLua,2);
				P2 arg2 = LuaDataType<P2>::get(lpLua,3);
				P3 arg3 = LuaDataType<P3>::get(lpLua,4);
				P4 arg4 = LuaDataType<P4>::get(lpLua,5);
				P5 arg5 = LuaDataType<P5>::get(lpLua,6);
				lpFunction(arg0,arg1,arg2,arg3,arg4,arg5);
				return 0;
			}
		};



		/*
		//	Function used to safely call
		//	functions wich could possibly
		//	have a void return type
		//	7 Arguments
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		struct SafeCall_7
		{
			int operator()(Lua* lpLua, R(*lpFunction)(P0, P1, P2, P3, P4, P5, P6))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua,1);
				P1 arg1 = LuaDataType<P1>::get(lpLua,2);
				P2 arg2 = LuaDataType<P2>::get(lpLua,3);
				P3 arg3 = LuaDataType<P3>::get(lpLua,4);
				P4 arg4 = LuaDataType<P4>::get(lpLua,5);
				P5 arg5 = LuaDataType<P5>::get(lpLua,6);
				P6 arg6 = LuaDataType<P6>::get(lpLua,7);
				R returnArg = lpFunction(arg0,arg1,arg2,arg3,arg4,arg5,arg6);
				LuaDataType<R>::push(lpLua,returnArg);
				return 1;
			}
		};
		template<typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		struct SafeCall_7<void,P0,P1,P2,P3,P4,P5,P6>
		{
			int operator()(Lua* lpLua, void(*lpFunction)(P0, P1, P2, P3, P4, P5, P6))
			{
				P0 arg0 = LuaDataType<P0>::get(lpLua,1);
				P1 arg1 = LuaDataType<P1>::get(lpLua,2);
				P2 arg2 = LuaDataType<P2>::get(lpLua,3);
				P3 arg3 = LuaDataType<P3>::get(lpLua,4);
				P4 arg4 = LuaDataType<P4>::get(lpLua,5);
				P5 arg5 = LuaDataType<P5>::get(lpLua,6);
				P6 arg6 = LuaDataType<P6>::get(lpLua,7);
				lpFunction(arg0,arg1,arg2,arg3,arg4,arg5,arg6);
				return 0;
			}
		};

	}

}

#endif